余烬缀记

NodeJS Spawn 用法

edited on:

wallhaven-zx6xgg

在实现 CLI 的时候经常会出现调用命令的情况,本文将记录使用child_process.spawn时的心得,语法查看 Node JS 官方文档child_process.spawn

# 使用异步还是同步?

在编写 CLI 的时候一般都会使用一些动画,在终端上显示什么转圈圈啊,加载多少多少啊等等,如果使用同步就会导致这些动画卡住,为什么会卡住可以参考https://nodejs.org/zh-cn/docs/guides/blocking-vs-non-blocking/这里的说明,所以还是使用异步。

我只想简单的调用一个命令等它执行完再继续执行 JS,又不想使用同步就得使用 Promise 进行封装一下了

function exec(file, args, options) {
    let command = []
    if (Array.isArray(args)) {
      command = file.split(/\s+(?=(?:"[^"]+"|[^"])+$)/g).concat(args)
    } else {
      options = args
      command = file.split(/\s+(?=(?:"[^"]+"|[^"])+$)/g)
    }
    return new Promise((resolve, reject) => {
      const cmd = spawn(command.shift(), command, options)
      let stdout = ''
      let stderr = ''
      cmd.stdout.on('data', data => (stdout += data))
      cmd.stderr.on('data', data => (stderr += data))
      cmd.on('error', error => {
        reject(error)
      })
      cmd.on('exit', (code) => {
        if (code !== 0) reject(new Error(stderr))
        else resolve(stdout)
      })
    })
}

原生 spawn 是传入参数的,我不想将参数挨个写在数组里所以使用正则将其按空格划分,这里比较麻烦的就是引号的问题,自己苦苦思索半天毫无结果,谷歌一搜立马就出来个stackoverflow,果然我还是个弟弟...

# 设置 Windows CMD 的编码

在某些情况需要解析终端传递的数据时就需要设置编码,这里指 Windows,Windows 的终端编码默认是 GBK,打印出来就是一堆乱码。在https://ss64.com/nt/chcp.html我找到了 Windows 的编码代码,65001 就是 UTF-8 的代码

chcp 65001
await exec('chcp 65001')

# 管道符

在实现 TCP 检测的时候我使用到了 Windows 的端口查询语法

netstat -ano | findstr "8080"

这里用到了管道符,在一堆搜索后面我终于找到了如何使用 spawn 实现 windows 的管道符,这里就得拆分命令了,分别是netstat -ano打印所有端口信息和findstr "8080"搜索字符串

const netstat = spawn('netstat', ['-ano'])
const findstr = spawn('findstr', [port], {
   stdio: [netstat.stdout, 'pipe', process.stderr]
})
let stdout = ''
findstr.stdout.on('data', data => (stdout += data))
findstr.on('exit', () => {
    console.log(stdout)
})